home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Scrolling Panel
/
ScrollDialog.c
next >
Wrap
Text File
|
1994-07-19
|
15KB
|
570 lines
/***************************************************************************************
*
* ScrollDialog.c- A useful library for implementing scrollable text boxes in
* a dialog. Can be used for elaborate about boxes, etc.
*
* ©1993 by Graham Cox. All Rights Reserved.
*
* 20/3/93 Modified to allow edit operations if required.
* 10/2/94 Routines added to support SimpleHelp library
* 10/2/94 Dependency on xAlert library removed
* 13/7/94 Converted to Universal Headers and compiled for PowerPC
*
***************************************************************************************/
/*
Basic operation. This library requires that you set up a dialog box in a certain way in
order to use it properly. For versatility, both a high level and a low level interface
is provided, for the purposes for which this code was designed, the high level inter-
face is generally the most useful.
Putting scrollable styled text into a dialog is a bit of a chore, in that it requires
three tedious custom procedures- a user item proc to draw it, a filter proc to handle
the scroll bar properly, and a control action proc to scroll the text. By bundling these
functions into a high level dialog call, all this is taken care of for you. This library
can be used with most dialog templates, the only prerequisite is that you create a user
item to delineate the area to display the text as part of the dialog template. The
scrollbar is created for you at run time, and is positioned on the right of the useritem.
The high level call requires an ID for the template, the item number of the useritem
to use for the text, and the item number of a TEXT resource. The dialog is set up and
displayed, then handled. For this call, a hit in any enabled item will close the dialog
and return, so in this respect it acts like a special alert box. For more control, you
will need to handle hits yourself. The only restriction in this case is that you don't
require a custom filter yourself- as one is already in use, you will need to do every-
thing yourself if you need very complex dialog handling. In this case I would suggest
you use a window anyway.
*/
#include "ScrollDialog.h"
#include "ColourPopUp.h"
/****************************************************************************************
INTERNAL FUNCTIONS
*/
pascal void TDUserItem(DialogPtr theDialog,short theItem)
{
/* draws text in user item using textedit. Dialog's RefCon is handle to text rec */
short itemType;
Handle itemHand;
Rect itemBox;
TDRecHdl temp;
if (theDialog != NIL)
{
GetDItem(theDialog,theItem,&itemType,&itemHand,&itemBox);
temp = (TDRecHdl) GetWRefCon(theDialog);
if (temp != NIL)
{
//EraseRect(&itemBox);
TEUpdate(&itemBox,(*temp)->TDText);
}
Frame3DRect(&itemBox,FALSE);
FrameRect(&itemBox);
}
}
pascal void TDScrollProc(ControlHandle theControl,short partCode)
{
/* scrolls text when scroll bar is tracked */
short oldValue,newValue;
TDRecHdl temp;
TEHandle theText;
if (theControl != NIL)
{
temp = (TDRecHdl) GetCRefCon(theControl);
oldValue = newValue = GetCtlValue(theControl);
switch (partCode)
{
case inUpButton:
newValue -= (*temp)->lineHeight;
break;
case inDownButton:
newValue += (*temp)->lineHeight;
break;
case inPageUp:
newValue -= (*temp)->pageHeight;
break;
case inPageDown:
newValue += (*temp)->pageHeight;
break;
default:
break;
}
SetCtlValue(theControl,newValue);
newValue = GetCtlValue(theControl);
theText = (*temp)->TDText;
if (theText != NIL)
TEScroll(0,oldValue - newValue,theText);
}
}
pascal Boolean TDFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
{
/* this is the filter proc to implement auto scrolling and everything else */
Point mClick;
ControlHandle theControl = NIL;
short partCode,itemType,ctlShift;
char theKey;
Handle itemHand;
Rect itemBox;
long dTime;
TEHandle theText;
TDRecHdl temp;
GrafPtr savePort;
Boolean canWrite;
CursHandle theCursor;
ControlActionUPP gVActionUPP;
if (theDialog != NIL)
{
GetPort(&savePort);
SetPort(theDialog);
temp = (TDRecHdl) GetWRefCon(theDialog);
if (temp != NIL)
{
theText = (*temp)->TDText;
canWrite = (*temp)->editable;
if (canWrite)
{
TEIdle(theText);
GetMouse(&mClick);
if (PtInRect(mClick,&(*theText)->viewRect))
{
theCursor = GetCursor(iBeamCursor);
SetCursor (*theCursor);
}
else
InitCursor();
}
switch (theEvent->what)
{
case mouseDown:
mClick = theEvent->where;
GlobalToLocal(&mClick);
partCode = FindControl(mClick,theDialog,&theControl);
if ((theControl != NIL) && (theControl == (*temp)->TDControl))
{
if (partCode == inThumb)
{
*itemHit = 0;
ctlShift = GetCtlValue(theControl);
partCode = TrackControl(theControl,mClick,NIL);
if (partCode == inThumb) {
ctlShift -= GetCtlValue(theControl);
TEScroll(0,ctlShift,theText);
}
}
else
{
gVActionUPP = NewControlActionProc((ProcPtr) TDScrollProc);
partCode = TrackControl(theControl,mClick,gVActionUPP);
DisposeRoutineDescriptor(gVActionUPP);
*itemHit = 0;
}
SetPort(savePort);
return(TRUE);
}
else
{
/* not our special scrollbar, so just return FALSE, let it be handled
by the dialog manager- it doesn't do a lot for its living */
if (canWrite)
{
if (PtInRect(mClick,&(*theText)->viewRect))
{
TEClick(mClick,(theEvent->modifiers & shiftKey) == shiftKey,theText);
UpdateTDBar(theText,(*temp)->TDControl);
}
}
SetPort(savePort);
return(FALSE);
}
break;
case keyDown:
case autoKey:
theKey = theEvent->message & charCodeMask;
if (canWrite)
{
/* edit flag TRUE, so pass key presses to text */
TEKey(theKey,theText);
UpdateTDBar(theText,(*temp)->TDControl);
}
else
{
if (theKey == 0x0D || theKey == 0x03)
{
GetDItem(theDialog,1,&itemType,&itemHand,&itemBox);
HiliteControl((ControlHandle)itemHand,1);
Delay(8,&dTime);
HiliteControl((ControlHandle)itemHand,0);
*itemHit = 1;
SetPort(savePort);
return(TRUE);
}
}
break;
default:
break;
}
}
SetPort(savePort);
}
return(FALSE);
}
pascal DialogPtr GetTextDialog(short dialogID,short textUserItem,short textResourceID,Boolean canWrite)
{
/* gets a dialog of the required ID, then sets up the given user item as a scrollable
text item using the text resource passed. If the text resource doesn't exist,
then you'll need to install the text yourself */
DialogPtr theDialog = NIL;
TDRecHdl temp;
TEHandle theText;
ControlHandle tdBar;
short itemType,tHeight;
Handle itemHand,textRes;
Rect itemBox,tdBarRect;
GrafPtr savePort;
StScrpHandle stRec = NIL;
FontInfo fInfo;
short saveFont,saveSize,saveFace;
static UserItemUPP gMyUserItemUPP;
theDialog = GetNewDialog(dialogID,NIL,(WindowPtr) -1L);
if (theDialog != NIL)
{
GetDItem(theDialog,textUserItem,&itemType,&itemHand,&itemBox);
GetPort(&savePort);
SetPort(theDialog);
if ((itemType & 0x007F) == userItem)
{
/* it really is a user item so set its procedure up */
temp = (TDRecHdl) NewHandle(sizeof(TDRecord));
SetWRefCon(theDialog,(long) temp);
if (temp != NIL)
{
saveFont = theDialog->txFont;
saveSize = theDialog->txSize;
saveFace = theDialog->txFace;
gMyUserItemUPP = NewUserItemProc((ProcPtr) TDUserItem);
itemHand = (Handle) gMyUserItemUPP;
SetDItem(theDialog,textUserItem,itemType,itemHand,&itemBox);
TextFont(geneva);
TextSize(9);
GetFontInfo(&fInfo);
SetRect(&tdBarRect,0,0,16,itemBox.bottom - itemBox.top);
itemBox.right -= 16;
OffsetRect(&tdBarRect,itemBox.right,itemBox.top);
InsetRect(&itemBox,3,3);
(*temp)->lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
(*temp)->pageHeight = (itemBox.bottom - itemBox.top) -
(*temp)->lineHeight;
(*temp)->editable = canWrite;
theText = TEStylNew(&itemBox,&itemBox);
tdBar = NewControl(theDialog,&tdBarRect,"\p",TRUE,0,0,100,16,0);
(*temp)->TDText = theText;
(*temp)->TDControl = tdBar;
(*temp)->reserved = 0;
/* ready to go- try loading the text */
if (theText != NIL)
{
textRes = GetResource('TEXT',textResourceID);
if (textRes != NIL)
{
stRec = (StScrpHandle) GetResource('styl',textResourceID);
HLock(textRes);
TEStylInsert(*textRes,GetHandleSize(textRes),stRec,theText);
HUnlock(textRes);
ReleaseResource(textRes);
if (stRec != NIL)
ReleaseResource((Handle) stRec);
}
tHeight = TEGetHeight(0,32767,theText) -
(itemBox.bottom - itemBox.top);
if (tHeight < 0)
tHeight = 0;
if (tdBar != NIL)
{
SetCtlMax(tdBar,tHeight);
SetCRefCon(tdBar,(long) temp);
}
if (canWrite)
{
TEAutoView(TRUE,theText);
TEActivate(theText);
}
}
TextFont(saveFont);
TextSize(saveSize);
TextFace(saveFace);
}
SetPort(savePort);
}
}
return(theDialog);
}
pascal void DisposeTDDialog(DialogPtr theDialog)
{
/* disposes of dialog and all internal structures created */
TDRecHdl temp;
TEHandle theText;
ControlHandle tdBar;
if (theDialog != NIL)
{
temp = (TDRecHdl) GetWRefCon(theDialog);
if (temp != NIL)
{
theText = (*temp)->TDText;
tdBar = (*temp)->TDControl;
if (theText != NIL)
TEDispose(theText);
if (tdBar != NIL)
DisposeControl(tdBar);
DisposHandle((Handle)temp);
}
DisposDialog(theDialog);
}
}
pascal void ModalTDDialog(short *theItem)
{
ModalFilterUPP gTDFilterUPP;
gTDFilterUPP = NewModalFilterProc((ProcPtr) TDFilter);
ModalDialog(gTDFilterUPP,theItem);
DisposeRoutineDescriptor(gTDFilterUPP);
}
pascal short ScrollTextDialog(short dialogID,short textUserItem,short textResourceID)
{
/* high level alert-like call to display scrolly text dialog box */
DialogPtr theDialog;
Handle itemHand;
Rect itemBox;
short theItem = 0,itemType;
GrafPtr savePort;
theDialog = GetTextDialog(dialogID,textUserItem,textResourceID,FALSE);
if (theDialog != NIL)
{
ShowWindow(theDialog);
SelectWindow(theDialog);
GetDItem(theDialog,ok,&itemType,&itemHand,&itemBox);
InsetRect(&itemBox,-4,-4);
GetPort(&savePort);
SetPort(theDialog);
PenSize(3,3);
FrameRoundRect(&itemBox,16,16);
PenNormal();
SetPort(savePort);
while (theItem == 0)
ModalTDDialog(&theItem);
DisposeTDDialog(theDialog);
}
return(theItem);
}
pascal void TDSetText(DialogPtr theDialog,Ptr text,long tLength,StScrpHandle stInfo)
{
/* sets the text in the TD dialog to be the given text. If you pass a style record
the text will be styled using that record. The scrollbar etc is recalculated
for the amount of text, and reset to the first line. Using this, multi-page
scrollable text can be implemented */
TDRecHdl temp;
TEHandle theText;
ControlHandle tdBar;
short tHeight;
Rect tdBarRect;
GrafPtr savePort;
if (theDialog != NIL)
{
temp = (TDRecHdl) GetWRefCon(theDialog);
if (temp != NIL)
{
theText = (*temp)->TDText;
if (theText != NIL)
{
if ((*temp)->editable)
TEDeactivate(theText);
(*theText)->destRect = (*theText)->viewRect;
TESetSelect(0,32767,theText);
TEDelete(theText);
GetPort(&savePort);
SetPort(theDialog);
if (stInfo == NIL)
{
TESetText(text,tLength,theText);
InvalRect(&(*theText)->viewRect);
}
else
TEStylInsert(text,tLength,stInfo,theText);
TECalText(theText);
tdBar = (*temp)->TDControl;
SetPort(savePort);
if (tdBar != NIL)
{
tdBarRect = (*tdBar)->contrlRect;
InsetRect(&tdBarRect,0,3);
tHeight = TEGetHeight(0,32767,theText) -
(tdBarRect.bottom - tdBarRect.top);
if (tHeight < 0)
tHeight = 0;
SetCtlMax(tdBar,tHeight);
SetCtlValue(tdBar,0);
}
if ((*temp)->editable)
TEActivate(theText);
}
}
}
}
pascal void TDSetResourceText(DialogPtr theDialog,short textResID)
{
/* gets a 'TEXT' resource (& 'styl' if available) and calls TDSetText with it */
Handle text,style;
text = GetResource('TEXT',textResID);
if (text != NIL)
{
style = GetResource('styl',textResID);
HLock(text);
TDSetText(theDialog,*text,GetHandleSize(text),(StScrpHandle) style);
HUnlock(text);
ReleaseResource(text);
if (style != NIL)
ReleaseResource(style);
}
}
pascal TEHandle GetTDTextHdl(DialogPtr theDialog)
{
/* utility to return text handle for direct manipulation */
TDRecHdl temp;
TEHandle theText = NIL;
if (theDialog != NIL)
{
temp = (TDRecHdl) GetWRefCon(theDialog);
if (temp != NIL)
theText = (*temp)->TDText;
}
return(theText);
}
pascal void UpdateTDBar(TEHandle theText,ControlHandle theBar)
{
/* calculates how much the text record is scrolled and updates the scrollbar. This is
done after an autoscroll operation */
short pOffset,tHeight;
Rect tdBarRect;
tdBarRect = (*theBar)->contrlRect;
InsetRect(&tdBarRect,0,3);
tHeight = TEGetHeight(0,32767,theText) -
(tdBarRect.bottom - tdBarRect.top);
if (tHeight < 0)
tHeight = 0;
SetCtlMax(theBar,tHeight);
pOffset = (*theText)->viewRect.top - (*theText)->destRect.top;
SetCtlValue(theBar,pOffset);
}
pascal void RecalTDBar(DialogPtr theDialog)
{
/* recomputes parameters for the scroll bar. This is necessary if you change anything
during editing of the text */
TDRecHdl temp;
if (theDialog != NIL)
{
temp = (TDRecHdl)GetWRefCon(theDialog);
if (temp != NIL)
UpdateTDBar((*temp)->TDText,(*temp)->TDControl);
}
}
/*----------------------------------------------------------------------------------------
Support added for modeless dialog 10/2/94
----------------------------------------------------------------------------------------*/
pascal Boolean ModelessText(DialogPtr theDialog,short theItem,EventRecord *theEvent)
{
/* handles the modeless dialog case. This function should be called when DIALOGSELECT
returns a value of TRUE, for a dialog containing a text panel. This handles the
hits in the panel as for the modal case, and editing if that is enabled. If some
other item in the dialog is hit, then the function returns FALSE and you must then
handle it yourself. WARNING!!! The dialog passed MUST be a scrolly-text type. It is
your responsibility to check first.
*/
if (theDialog != NIL)
{
return(TDFilter(theDialog,theEvent,&theItem));
}
}